
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>9. 类 &#8212; Python 3.7.3 文档</title>
    <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <script type="text/javascript" src="../_static/translations.js"></script>
    
    <script type="text/javascript" src="../_static/sidebar.js"></script>
    
    <link rel="search" type="application/opensearchdescription+xml"
          title="在 Python 3.7.3 文档 中搜索"
          href="../_static/opensearch.xml"/>
    <link rel="author" title="关于这些文档" href="../about.html" />
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="copyright" title="版权所有" href="../copyright.html" />
    <link rel="next" title="10. 标准库简介" href="stdlib.html" />
    <link rel="prev" title="8. 错误和异常" href="errors.html" />
    <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
    <link rel="canonical" href="https://docs.python.org/3/tutorial/classes.html" />
    
    <script type="text/javascript" src="../_static/copybutton.js"></script>
    <script type="text/javascript" src="../_static/switchers.js"></script>
    
    
    
    <style>
      @media only screen {
        table.full-width-table {
            width: 100%;
        }
      }
    </style>
 

  </head><body>  
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>导航</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="总目录"
             accesskey="I">索引</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python 模块索引"
             >模块</a> |</li>
        <li class="right" >
          <a href="stdlib.html" title="10. 标准库简介"
             accesskey="N">下一页</a> |</li>
        <li class="right" >
          <a href="errors.html" title="8. 错误和异常"
             accesskey="P">上一页</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="https://www.python.org/">Python</a> &#187;</li>
        <li>
          <span class="language_switcher_placeholder">zh_CN</span>
          <span class="version_switcher_placeholder">3.7.3</span>
          <a href="../index.html">文档</a> &#187;
        </li>

          <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 教程</a> &#187;</li>
    <li class="right">
        

    <div class="inline-search" style="display: none" role="search">
        <form class="inline-search" action="../search.html" method="get">
          <input placeholder="快速搜索" type="text" name="q" />
          <input type="submit" value="转向" />
          <input type="hidden" name="check_keywords" value="yes" />
          <input type="hidden" name="area" value="default" />
        </form>
    </div>
    <script type="text/javascript">$('.inline-search').show(0);</script>
         |
    </li>

      </ul>
    </div>    

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <div class="section" id="classes">
<span id="tut-classes"></span><h1>9. 类<a class="headerlink" href="#classes" title="永久链接至标题">¶</a></h1>
<p>类提供了一种组合数据和功能的方法。创建一个新类意味着创建一个新 <em>类型</em> 的对象，从而允许创建一个该类型的新 <em>实例</em> 。每个类的实例可以拥有保存自己状态的属性。一个类的实例也可以有改变自己状态的（定义在类中的）方法。</p>
<p>和其他编程语言相比，Python 用非常少的新语法和语义将类加入到语言中。它是 C++ 和 Modula-3 中类机制的结合。Python 的类提供了面向对象编程的所有标准特性：类继承机制允许多个基类，派生类可以覆盖它基类的任何方法，一个方法可以调用基类中相同名称的的方法。对象可以包含任意数量和类型的数据。和模块一样，类也拥有 Python 天然的动态特性：它们在运行时创建，可以在创建后修改。</p>
<p>在C++术语中，通常类成员（包括数据成员）是 <em>public</em> （除了见下文 <a class="reference internal" href="#tut-private"><span class="std std-ref">私有变量</span></a> ），所有成员函数都是 <em>virtual</em> 。与在Modula-3中一样，没有用于从其方法引用对象成员的简写：方法函数使用表示对象的显式第一个参数声明，该参数由调用隐式提供。与Smalltalk一样，类本身也是对象。这为导入和重命名提供了语义。与C++和Modula-3不同，内置类型可以用作用户扩展的基类。此外，与C++一样，大多数具有特殊语法（算术运算符，下标等）的内置运算符都可以重新定义为类实例。</p>
<p>(Lacking universally accepted terminology to talk about classes, I will make
occasional use of Smalltalk and C++ terms.  I would use Modula-3 terms, since
its object-oriented semantics are closer to those of Python than C++, but I
expect that few readers have heard of it.)</p>
<div class="section" id="a-word-about-names-and-objects">
<span id="tut-object"></span><h2>9.1. 名称和对象<a class="headerlink" href="#a-word-about-names-and-objects" title="永久链接至标题">¶</a></h2>
<p>对象具有个性，多个名称（在多个作用域内）可以绑定到同一个对象。这在其他语言中称为别名。乍一看Python时通常不会理解这一点，在处理不可变的基本类型（数字，字符串，元组）时可以安全地忽略它。但是，别名对涉及可变对象，如列表，字典和大多数其他类型，的Python代码的语义可能会产生惊人的影响。这通常用于程序的好处，因为别名在某些方面表现得像指针。例如，传递一个对象很便宜，因为实现只传递一个指针；如果函数修改了作为参数传递的对象，调用者将看到更改 --- 这就不需要像 Pascal 中那样使用两个不同的参数传递机制。</p>
</div>
<div class="section" id="python-scopes-and-namespaces">
<span id="tut-scopes"></span><h2>9.2. Python 作用域和命名空间<a class="headerlink" href="#python-scopes-and-namespaces" title="永久链接至标题">¶</a></h2>
<p>在介绍类之前，我首先要告诉你一些Python的作用域规则。类定义对命名空间有一些巧妙的技巧，你需要知道作用域和命名空间如何工作才能完全理解正在发生的事情。顺便说一下，关于这个主题的知识对任何高级Python程序员都很有用。</p>
<p>让我们从一些定义开始。</p>
<p><em>namespace</em> 是一个从名字到对象的映射。大部分命名空间当前都由 Python 字典实现，但一般情况下基本不会去关注它们（除了要面对性能问题时），而且也有可能在将来更改。下面是几个命名空间的例子：存放内置函数的集合（包含 <a class="reference internal" href="../library/functions.html#abs" title="abs"><code class="xref py py-func docutils literal notranslate"><span class="pre">abs()</span></code></a> 这样的函数，和内建的异常等）；模块中的全局名称；函数调用中的本地名称。从某种意义上说，对象的的属性集合也是一种命名空间的形式。关于命名空间的重要一点是，不同命名空间中的名称之间绝对没有关系；例如，两个不同的模块都可以定义函数“最大化”而不会产生混淆 - 模块的用户必须在其前面加上模块名称。</p>
<p>顺便说明一下，我把任何跟在一个点号之后的名称都称为 <em>属性</em> --- 例如，在表达式 <code class="docutils literal notranslate"><span class="pre">z.real</span></code> 中，<code class="docutils literal notranslate"><span class="pre">real</span></code> 是对象 <code class="docutils literal notranslate"><span class="pre">z</span></code> 的一个属性。按严格的说法，对模块中名称的引用属于属性引用：在表达式 <code class="docutils literal notranslate"><span class="pre">modname.funcname</span></code> 中，<code class="docutils literal notranslate"><span class="pre">modname</span></code> 是一个模块对象而 <code class="docutils literal notranslate"><span class="pre">funcname</span></code> 是它的一个属性。在此情况下在模块的属性和模块中定义的全局名称之间正好存在一个直观的映射：它们共享相同的命名空间！ <a class="footnote-reference" href="#id2" id="id1">[1]</a></p>
<p>属性可以是只读或者可写的。如果为后者，那么对属性的赋值是可行的。模块属性是可以写，你可以写出 <code class="docutils literal notranslate"><span class="pre">modname.the_answer</span> <span class="pre">=</span> <span class="pre">42</span></code> 。可写的属性同样可以用 <a class="reference internal" href="../reference/simple_stmts.html#del"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">del</span></code></a> 语句删除。例如， <code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">modname.the_answer</span></code> 将会从名为 <code class="docutils literal notranslate"><span class="pre">modname</span></code> 的对象中移除 <code class="xref py py-attr docutils literal notranslate"><span class="pre">the_answer</span></code> 属性。</p>
<p>在不同时刻创建的命名空间拥有不同的生存期。包含内置名称的命名空间是在 Python 解释器启动时创建的，永远不会被删除。模块的全局命名空间在模块定义被读入时创建；通常，模块命名空间也会持续到解释器退出。被解释器的顶层调用执行的语句，从一个脚本文件读取或交互式地读取，被认为是 <a class="reference internal" href="../library/__main__.html#module-__main__" title="__main__: The environment where the top-level script is run."><code class="xref py py-mod docutils literal notranslate"><span class="pre">__main__</span></code></a> 模块调用的一部分，因此它们拥有自己的全局命名空间。（内置名称实际上也存在于一个模块中；这个模块称作 <a class="reference internal" href="../library/builtins.html#module-builtins" title="builtins: The module that provides the built-in namespace."><code class="xref py py-mod docutils literal notranslate"><span class="pre">builtins</span></code></a> 。）</p>
<p>一个函数的本地命名空间在这个函数被调用时创建，并在函数返回或抛出一个不在函数内部处理的错误时被删除。（事实上，比起描述到底发生了什么，忘掉它更好。）当然，每次递归调用都会有它自己的本地命名空间。</p>
<p>一个 <em>作用域</em> 是一个命名空间可直接访问的 Python 程序的文本区域。 这里的 “可直接访问” 意味着对名称的非限定引用会尝试在命名空间中查找名称。</p>
<p>Although scopes are determined statically, they are used dynamically. At any
time during execution, there are at least three nested scopes whose namespaces
are directly accessible:</p>
<ul class="simple">
<li>最先搜索的最内部作用域包含局部名称</li>
<li>从最近的封闭作用域开始搜索的任何封闭函数的范围包含非局部名称，也包括非全局名称</li>
<li>倒数第二个作用域包含当前模块的全局名称</li>
<li>最外面的范围（最后搜索）是包含内置名称的命名空间</li>
</ul>
<p>如果一个名称被声明为全局变量，则所有引用和赋值将直接指向包含该模块的全局名称的中间作用域。 要重新绑定在最内层作用域以外找到的变量，可以使用 <a class="reference internal" href="../reference/simple_stmts.html#nonlocal"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">nonlocal</span></code></a> 语句声明为非本地变量。 如果没有被声明为非本地变量，这些变量将是只读的（尝试写入这样的变量只会在最内层作用域中创建一个 <em>新的</em> 局部变量，而同名的外部变量保持不变）。</p>
<p>通常，当前局部作为域将（按字面文本）引用当前函数的局部名称。 在函数以外，局部作用域将引用与全局作用域相一致的命名空间：模块的命名空间。 类定义将在局部命名空间内再放置另一个命名空间。</p>
<p>重要的是应该意识到作用域是按字面文本来确定的：在一个模块内定义的函数的全局作用域就是该模块的命名空间，无论该函数从什么地方或以什么别名被调用。 另一方面，实际的名称搜索是在运行时动态完成的 --- 但是，语言定义在 <em>编译时</em> 是朝着静态名称解析的方向演化的，因此不要过于依赖动态名称解析！ （事实上，局部变量已经是被静态确定了。）</p>
<p>Python 的一个特殊之处在于 -- 如果不存在生效的 <a class="reference internal" href="../reference/simple_stmts.html#global"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">global</span></code></a> 语句 -- 对名称的赋值总是进入最内层作用域。 赋值不会复制数据 --- 它们只是将名称绑定到对象。 删除也是如此：语句 <code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">x</span></code> 会从局部命名空间的引用中移除对 <code class="docutils literal notranslate"><span class="pre">x</span></code> 的绑定。 事实上，所有引入新名称的操作都使用局部作用域：特别地，<a class="reference internal" href="../reference/simple_stmts.html#import"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> 语句和函数定义会在局部作用域中绑定模块或函数名称。</p>
<p><a class="reference internal" href="../reference/simple_stmts.html#global"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">global</span></code></a> 语句可被用来表明特定变量生存于全局作用域并且应当在其中被重新绑定；<a class="reference internal" href="../reference/simple_stmts.html#nonlocal"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">nonlocal</span></code></a> 语句表明特定变量生存于外层作用域中并且应当在其中被重新绑定。</p>
<div class="section" id="scopes-and-namespaces-example">
<span id="tut-scopeexample"></span><h3>9.2.1. 作用域和命名空间示例<a class="headerlink" href="#scopes-and-namespaces-example" title="永久链接至标题">¶</a></h3>
<p>This is an example demonstrating how to reference the different scopes and
namespaces, and how <a class="reference internal" href="../reference/simple_stmts.html#global"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">global</span></code></a> and <a class="reference internal" href="../reference/simple_stmts.html#nonlocal"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">nonlocal</span></code></a> affect variable
binding:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">scope_test</span><span class="p">():</span>
    <span class="k">def</span> <span class="nf">do_local</span><span class="p">():</span>
        <span class="n">spam</span> <span class="o">=</span> <span class="s2">&quot;local spam&quot;</span>

    <span class="k">def</span> <span class="nf">do_nonlocal</span><span class="p">():</span>
        <span class="k">nonlocal</span> <span class="n">spam</span>
        <span class="n">spam</span> <span class="o">=</span> <span class="s2">&quot;nonlocal spam&quot;</span>

    <span class="k">def</span> <span class="nf">do_global</span><span class="p">():</span>
        <span class="k">global</span> <span class="n">spam</span>
        <span class="n">spam</span> <span class="o">=</span> <span class="s2">&quot;global spam&quot;</span>

    <span class="n">spam</span> <span class="o">=</span> <span class="s2">&quot;test spam&quot;</span>
    <span class="n">do_local</span><span class="p">()</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;After local assignment:&quot;</span><span class="p">,</span> <span class="n">spam</span><span class="p">)</span>
    <span class="n">do_nonlocal</span><span class="p">()</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;After nonlocal assignment:&quot;</span><span class="p">,</span> <span class="n">spam</span><span class="p">)</span>
    <span class="n">do_global</span><span class="p">()</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;After global assignment:&quot;</span><span class="p">,</span> <span class="n">spam</span><span class="p">)</span>

<span class="n">scope_test</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;In global scope:&quot;</span><span class="p">,</span> <span class="n">spam</span><span class="p">)</span>
</pre></div>
</div>
<p>示例代码的输出是：</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
</pre></div>
</div>
<p>请注意 <em>局部</em> 赋值（这是默认状态）不会改变 <em>scope_test</em> 对 <em>spam</em> 的绑定。 <a class="reference internal" href="../reference/simple_stmts.html#nonlocal"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">nonlocal</span></code></a> 赋值会改变 <em>scope_test</em> 对 <em>spam</em> 的绑定，而 <a class="reference internal" href="../reference/simple_stmts.html#global"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">global</span></code></a> 赋值会改变模块层级的绑定。</p>
<p>您还可以在 <a class="reference internal" href="../reference/simple_stmts.html#global"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">global</span></code></a> 赋值之前看到之前没有 <em>spam</em> 的绑定。</p>
</div>
</div>
<div class="section" id="a-first-look-at-classes">
<span id="tut-firstclasses"></span><h2>9.3. 初探类<a class="headerlink" href="#a-first-look-at-classes" title="永久链接至标题">¶</a></h2>
<p>类引入了一些新语法，三种新对象类型和一些新语义。</p>
<div class="section" id="class-definition-syntax">
<span id="tut-classdefinition"></span><h3>9.3.1. 类定义语法<a class="headerlink" href="#class-definition-syntax" title="永久链接至标题">¶</a></h3>
<p>最简单的类定义看起来像这样:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassName</span><span class="p">:</span>
    <span class="o">&lt;</span><span class="n">statement</span><span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span>
    <span class="o">.</span>
    <span class="o">.</span>
    <span class="o">.</span>
    <span class="o">&lt;</span><span class="n">statement</span><span class="o">-</span><span class="n">N</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>类定义与函数定义 (<a class="reference internal" href="../reference/compound_stmts.html#def"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">def</span></code></a> 语句) 一样必须被执行才会起作用。 （你可以尝试将类定义放在 <a class="reference internal" href="../reference/compound_stmts.html#if"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">if</span></code></a> 语句的一个分支或是函数的内部。）</p>
<p>在实践中，类定义内的语句通常都是函数定义，但也允许有其他语句，有时还很有用 --- 我们会稍后再回来说明这个问题。 在类内部的函数定义通常具有一种特别形式的参数列表，这是方法调用的约定规范所指明的 --- 这个问题也将在稍后再说明。</p>
<p>当进入类定义时，将创建一个新的命名空间，并将其用作局部作用域 --- 因此，所有对局部变量的赋值都是在这个新命名空间之内。 特别的，函数定义会绑定到这里的新函数名称。</p>
<p>当（从结尾处）正常离开类定义时，将创建一个 <em>类对象</em>。 这基本上是一个包围在类定义所创建命名空间内容周围的包装器；我们将在下一节了解有关类对象的更多信息。 原始的（在进入类定义之前起作用的）局部作用域将重新生效，类对象将在这里被绑定到类定义头所给出的类名称 (在这个示例中为 <code class="xref py py-class docutils literal notranslate"><span class="pre">ClassName</span></code>)。</p>
</div>
<div class="section" id="class-objects">
<span id="tut-classobjects"></span><h3>9.3.2. 类对象<a class="headerlink" href="#class-objects" title="永久链接至标题">¶</a></h3>
<p>类对象支持两种操作：属性引用和实例化。</p>
<p><em>属性引用</em> 使用 Python 中所有属性引用所使用的标准语法: <code class="docutils literal notranslate"><span class="pre">obj.name</span></code>。 有效的属性名称是类对象被创建时存在于类命名空间中的所有名称。 因此，如果类定义是这样的:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;A simple example class&quot;&quot;&quot;</span>
    <span class="n">i</span> <span class="o">=</span> <span class="mi">12345</span>

    <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s1">&#39;hello world&#39;</span>
</pre></div>
</div>
<p>那么 <code class="docutils literal notranslate"><span class="pre">MyClass.i</span></code> 和 <code class="docutils literal notranslate"><span class="pre">MyClass.f</span></code> 就是有效的属性引用，将分别返回一个整数和一个函数对象。 类属性也可以被赋值，因此可以通过赋值来更改 <code class="docutils literal notranslate"><span class="pre">MyClass.i</span></code> 的值。 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__doc__</span></code> 也是一个有效的属性，将返回所属类的文档字符串: <code class="docutils literal notranslate"><span class="pre">&quot;A</span> <span class="pre">simple</span> <span class="pre">example</span> <span class="pre">class&quot;</span></code>。</p>
<p>类的 <em>实例化</em> 是使用函数表示法。 可以相像类对象就是会返回一个新的类实例的不带参数的函数。 举例来说（假设使用上述的类）:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="n">MyClass</span><span class="p">()</span>
</pre></div>
</div>
<p>创建类的新 <em>实例</em> 并将此对象分配给局部变量 <code class="docutils literal notranslate"><span class="pre">x</span></code>。</p>
<p>实例化操作（“调用”类对象）会创建一个空对象。 许多类喜欢创建带有特定初始状态的自定义实例。 为此类定义可能包含一个名为 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> 的特殊方法，就像这样:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span>
</pre></div>
</div>
<p>当一个类定义了 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> 方法时，类的实例化操作会自动为新创建的类实例发起调用 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a>。 因此在这个示例中，可以通过以下语句获得一个经初始化的新实例:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="n">MyClass</span><span class="p">()</span>
</pre></div>
</div>
<p>当然，<a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> 方法还可以有额外参数以实现更高灵活性。 在这种情况下，提供给类实例化运算符的参数将被传递给 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a>。 例如，:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Complex</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">realpart</span><span class="p">,</span> <span class="n">imagpart</span><span class="p">):</span>
<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">r</span> <span class="o">=</span> <span class="n">realpart</span>
<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">i</span> <span class="o">=</span> <span class="n">imagpart</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="n">Complex</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">4.5</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span><span class="o">.</span><span class="n">r</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">i</span>
<span class="go">(3.0, -4.5)</span>
</pre></div>
</div>
</div>
<div class="section" id="instance-objects">
<span id="tut-instanceobjects"></span><h3>9.3.3. 实例对象<a class="headerlink" href="#instance-objects" title="永久链接至标题">¶</a></h3>
<p>现在我们可以用实例对象做什么？实例对象理解的唯一操作是属性引用。有两种有效的属性名称，数据属性和方法。</p>
<p><em>数据属性</em> 对应于 Smalltalk 中的“实例变量”，以及 C++ 中的“数据成员”。 数据属性不需要声明；像局部变量一样，它们将在第一次被赋值时产生。 例如，如果 <code class="docutils literal notranslate"><span class="pre">x</span></code> 是上面创建的 <code class="xref py py-class docutils literal notranslate"><span class="pre">MyClass</span></code> 的实例，则以下代码段将打印数值 <code class="docutils literal notranslate"><span class="pre">16</span></code>，且不保留任何追踪信息:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">:</span>
    <span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">*</span> <span class="mi">2</span>
<span class="nb">print</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">counter</span><span class="p">)</span>
<span class="k">del</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span>
</pre></div>
</div>
<p>另一类实例属性引用称为 <em>方法</em>。 方法是“从属于”对象的函数。 （在 Python 中，方法这个术语并不是类实例所特有的：其他对方也可以有方法。 例如，列表对象具有 append, insert, remove, sort 等方法。 然而，在以下讨论中，我们使用方法一词将专指类实例对象的方法，除非另外显式地说明。）</p>
<p id="index-0">实例对象的有效方法名称依赖于其所属的类。 根据定义，一个类中所有是函数对象的属性都是定义了其实例的相应方法。 因此在我们的示例中，<code class="docutils literal notranslate"><span class="pre">x.f</span></code> 是有效的方法引用，因为 <code class="docutils literal notranslate"><span class="pre">MyClass.f</span></code> 是一个函数，而 <code class="docutils literal notranslate"><span class="pre">x.i</span></code> 不是方法，因为 <code class="docutils literal notranslate"><span class="pre">MyClass.i</span></code> 不是一个函数。 但是 <code class="docutils literal notranslate"><span class="pre">x.f</span></code> 与 <code class="docutils literal notranslate"><span class="pre">MyClass.f</span></code> 并不是一回事 --- 它是一个 <em>方法对象</em>，不是函数对象。</p>
</div>
<div class="section" id="method-objects">
<span id="tut-methodobjects"></span><h3>9.3.4. 方法对象<a class="headerlink" href="#method-objects" title="永久链接至标题">¶</a></h3>
<p>通常，方法在绑定后立即被调用:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="o">.</span><span class="n">f</span><span class="p">()</span>
</pre></div>
</div>
<p>在 <code class="xref py py-class docutils literal notranslate"><span class="pre">MyClass</span></code> 示例中，这将返回字符串 <code class="docutils literal notranslate"><span class="pre">'hello</span> <span class="pre">world'</span></code>。 但是，立即调用一个方法并不是必须的: <code class="docutils literal notranslate"><span class="pre">x.f</span></code> 是一个方法对象，它可以被保存起来以后再调用。 例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">xf</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">f</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">xf</span><span class="p">())</span>
</pre></div>
</div>
<p>将继续打印 <code class="docutils literal notranslate"><span class="pre">hello</span> <span class="pre">world</span></code>，直到结束。</p>
<p>当一个方法被调用时到底发生了什么？ 你可能已经注意到上面调用 <code class="docutils literal notranslate"><span class="pre">x.f()</span></code> 时并没有带参数，虽然 <code class="xref py py-meth docutils literal notranslate"><span class="pre">f()</span></code> 的函数定义指定了一个参数。 这个参数发生了什么事？ 当不带参数地调用一个需要参数的函数时 Python 肯定会引发异常 --- 即使参数实际未被使用...</p>
<p>实际上，你可能已经猜到了答案：方法的特殊之处就在于实例对象会作为函数的第一个参数被传入。 在我们的示例中，调用 <code class="docutils literal notranslate"><span class="pre">x.f()</span></code> 其实就相当于 <code class="docutils literal notranslate"><span class="pre">MyClass.f(x)</span></code>。 总之，调用一个具有 <em>n</em> 个参数的方法就相当于调用再多一个参数的对应函数，这个参数值为方法所属实例对象，位置在其他参数之前。</p>
<p>如果你仍然无法理解方法的运作原理，那么查看实现细节可能会澄清问题。 当一个实例的非数据属性被引用时，将搜索实例所属的类。 如果名称表示一个属于函数对象的有效类属性，会通过合并打包（指向）实例对象和函数对象到一个抽象对象中的方式来创建一个方法对象：这个抽象对象就是方法对象。 当附带参数列表调用方法对象时，将基于实例对象和参数列表构建一个新的参数列表，并使用这个新参数列表调用相应的函数对象。</p>
</div>
<div class="section" id="class-and-instance-variables">
<span id="tut-class-and-instance-variables"></span><h3>9.3.5. 类和实例变量<a class="headerlink" href="#class-and-instance-variables" title="永久链接至标题">¶</a></h3>
<p>一般来说，实例变量用于每个实例的唯一数据，而类变量用于类的所有实例共享的属性和方法:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Dog</span><span class="p">:</span>

    <span class="n">kind</span> <span class="o">=</span> <span class="s1">&#39;canine&#39;</span>         <span class="c1"># class variable shared by all instances</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>    <span class="c1"># instance variable unique to each instance</span>

<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Fido&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Buddy&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">kind</span>                  <span class="c1"># shared by all dogs</span>
<span class="s1">&#39;canine&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">kind</span>                  <span class="c1"># shared by all dogs</span>
<span class="s1">&#39;canine&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">name</span>                  <span class="c1"># unique to d</span>
<span class="s1">&#39;Fido&#39;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">name</span>                  <span class="c1"># unique to e</span>
<span class="s1">&#39;Buddy&#39;</span>
</pre></div>
</div>
<p>正如 <a class="reference internal" href="#tut-object"><span class="std std-ref">名称和对象</span></a> 中已讨论过的，共享数据可能在涉及 <a class="reference internal" href="../glossary.html#term-mutable"><span class="xref std std-term">mutable</span></a> 对象例如列表和字典的时候导致令人惊讶的结果。 例如以下代码中的 <em>tricks</em> 列表不应该被用作类变量，因为所有的 <em>Dog</em> 实例将只共享一个单独的列表:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Dog</span><span class="p">:</span>

    <span class="n">tricks</span> <span class="o">=</span> <span class="p">[]</span>             <span class="c1"># mistaken use of a class variable</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>

    <span class="k">def</span> <span class="nf">add_trick</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">trick</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tricks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">trick</span><span class="p">)</span>

<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Fido&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Buddy&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">add_trick</span><span class="p">(</span><span class="s1">&#39;roll over&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">add_trick</span><span class="p">(</span><span class="s1">&#39;play dead&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">tricks</span>                <span class="c1"># unexpectedly shared by all dogs</span>
<span class="p">[</span><span class="s1">&#39;roll over&#39;</span><span class="p">,</span> <span class="s1">&#39;play dead&#39;</span><span class="p">]</span>
</pre></div>
</div>
<p>正确的类设计应该使用实例变量:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Dog</span><span class="p">:</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tricks</span> <span class="o">=</span> <span class="p">[]</span>    <span class="c1"># creates a new empty list for each dog</span>

    <span class="k">def</span> <span class="nf">add_trick</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">trick</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tricks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">trick</span><span class="p">)</span>

<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Fido&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Buddy&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">add_trick</span><span class="p">(</span><span class="s1">&#39;roll over&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">add_trick</span><span class="p">(</span><span class="s1">&#39;play dead&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">tricks</span>
<span class="p">[</span><span class="s1">&#39;roll over&#39;</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">tricks</span>
<span class="p">[</span><span class="s1">&#39;play dead&#39;</span><span class="p">]</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="random-remarks">
<span id="tut-remarks"></span><h2>9.4. 补充说明<a class="headerlink" href="#random-remarks" title="永久链接至标题">¶</a></h2>
<p>数据属性会覆盖掉具有相同名称的方法属性；为了避免会在大型程序中导致难以发现的错误的意外名称冲突，明智的做法是使用某种约定来最小化冲突的发生几率。 可能的约定包括方法名称使用大写字母，属性名称加上独特的短字符串前缀（或许只加一个下划线），或者是用动词来命名方法，而用名词来命名数据属性。</p>
<p>数据属性可以被方法以及一个对象的普通用户（“客户端”）所引用。 换句话说，类不能用于实现纯抽象数据类型。 实际上，在 Python 中没有任何东西能强制隐藏数据 --- 它是完全基于约定的。 （而在另一方面，用 C 语言编写的 Python 实现则可以完全隐藏实现细节，并在必要时控制对象的访问；此特性可以通过用 C 编写 Python 扩展来使用。）</p>
<p>客户端应当谨慎地使用数据属性 --- 客户端可能通过直接操作数据属性的方式破坏由方法所维护的固定变量。 请注意客户端可以向一个实例对象添加他们自己的数据属性而不会影响方法的可用性，只要保证避免名称冲突 --- 再次提醒，在此使用命名约定可以省去许多令人头痛的麻烦。</p>
<p>在方法内部引用数据属性（或其他方法！）并没有简便方式。 我发现这实际上提升了方法的可读性：当浏览一个方法代码时，不会存在混淆局部变量和实例变量的机会。</p>
<p>方法的第一个参数常常被命名为 <code class="docutils literal notranslate"><span class="pre">self</span></code>。 这也不过就是一个约定: <code class="docutils literal notranslate"><span class="pre">self</span></code> 这一名称在 Python 中绝对没有特殊含义。 但是要注意，不遵循此约定会使得你的代码对其他 Python 程序员来说缺乏可读性，而且也可以想像一个 <em>类浏览器</em> 程序的编写可能会依赖于这样的约定。</p>
<p>任何一个作为类属性的函数都为该类的实例定义了一个相应方法。 函数定义的文本并非必须包含于类定义之内：将一个函数对象赋值给一个局部变量也是可以的。 例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Function defined outside the class</span>
<span class="k">def</span> <span class="nf">f1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="nb">min</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
    <span class="n">f</span> <span class="o">=</span> <span class="n">f1</span>

    <span class="k">def</span> <span class="nf">g</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s1">&#39;hello world&#39;</span>

    <span class="n">h</span> <span class="o">=</span> <span class="n">g</span>
</pre></div>
</div>
<p>现在 <code class="docutils literal notranslate"><span class="pre">f</span></code>, <code class="docutils literal notranslate"><span class="pre">g</span></code> 和 <code class="docutils literal notranslate"><span class="pre">h</span></code> 都是 <code class="xref py py-class docutils literal notranslate"><span class="pre">C</span></code> 类的引用函数对象的属性，因而它们就都是 <code class="xref py py-class docutils literal notranslate"><span class="pre">C</span></code> 的实例的方法 --- 其中 <code class="docutils literal notranslate"><span class="pre">h</span></code> 完全等同于 <code class="docutils literal notranslate"><span class="pre">g</span></code>。 但请注意，本示例的做法通常只会令程序的阅读者感到迷惑。</p>
<p>方法可以通过使用 <code class="docutils literal notranslate"><span class="pre">self</span></code> 参数的方法属性调用其他方法:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Bag</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">addtwice</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</pre></div>
</div>
<p>方法可以通过与普通函数相同的方式引用全局名称。 与方法相关联的全局作用域就是包含其定义的模块。 （类永远不会被作为全局作用域。） 虽然我们很少会有充分的理由在方法中使用全局作用域，但全局作用域存在许多合法的使用场景：举个例子，导入到全局作用域的函数和模块可以被方法所使用，在其中定义的函数和类也一样。 通常，包含该方法的类本身是在全局作用域中定义的，而在下一节中我们将会发现为何方法需要引用其所属类的很好的理由。</p>
<p>每个值都是一个对象，因此具有 <em>类</em> （也称为 <em>类型</em>），并存储为 <code class="docutils literal notranslate"><span class="pre">object.__class__</span></code> 。</p>
</div>
<div class="section" id="inheritance">
<span id="tut-inheritance"></span><h2>9.5. 继承<a class="headerlink" href="#inheritance" title="永久链接至标题">¶</a></h2>
<p>当然，如果不支持继承，语言特性就不值得称为“类”。派生类定义的语法如下所示:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">DerivedClassName</span><span class="p">(</span><span class="n">BaseClassName</span><span class="p">):</span>
    <span class="o">&lt;</span><span class="n">statement</span><span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span>
    <span class="o">.</span>
    <span class="o">.</span>
    <span class="o">.</span>
    <span class="o">&lt;</span><span class="n">statement</span><span class="o">-</span><span class="n">N</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>名称 <code class="xref py py-class docutils literal notranslate"><span class="pre">BaseClassName</span></code> 必须定义于包含派生类定义的作用域中。 也允许用其他任意表达式代替基类名称所在的位置。 这有时也可能会用得上，例如，当基类定义在另一个模块中的时候:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">DerivedClassName</span><span class="p">(</span><span class="n">modname</span><span class="o">.</span><span class="n">BaseClassName</span><span class="p">):</span>
</pre></div>
</div>
<p>派生类定义的执行过程与基类相同。 当构造类对象时，基类会被记住。 此信息将被用来解析属性引用：如果请求的属性在类中找不到，搜索将转往基类中进行查找。 如果基类本身也派生自其他某个类，则此规则将被递归地应用。</p>
<p>派生类的实例化没有任何特殊之处: <code class="docutils literal notranslate"><span class="pre">DerivedClassName()</span></code> 会创建该类的一个新实例。 方法引用将按以下方式解析：搜索相应的类属性，如有必要将按基类继承链逐步向下查找，如果产生了一个函数对象则方法引用就生效。</p>
<p>派生类可能会重载其基类的方法。 因为方法在调用同一对象的其他方法时没有特殊权限，调用同一基类中定义的另一方法的基类方法最终可能会调用覆盖它的派生类的方法。 （对 C++ 程序员的提示：Python 中所有的方法实际上都是 <code class="docutils literal notranslate"><span class="pre">virtual</span></code> 方法。）</p>
<p>在派生类中的重载方法实际上可能想要扩展而非简单地替换同名的基类方法。 有一种方式可以简单地直接调用基类方法：即调用 <code class="docutils literal notranslate"><span class="pre">BaseClassName.methodname(self,</span> <span class="pre">arguments)</span></code>。 有时这对客户端来说也是有用的。 （请注意仅当此基类可在全局作用域中以 <code class="docutils literal notranslate"><span class="pre">BaseClassName</span></code> 的名称被访问时方可使用此方式。）</p>
<p>Python有两个内置函数可被用于继承机制：</p>
<ul class="simple">
<li>使用 <a class="reference internal" href="../library/functions.html#isinstance" title="isinstance"><code class="xref py py-func docutils literal notranslate"><span class="pre">isinstance()</span></code></a> 来检查一个实例的类型: <code class="docutils literal notranslate"><span class="pre">isinstance(obj,</span> <span class="pre">int)</span></code> 仅会在 <code class="docutils literal notranslate"><span class="pre">obj.__class__</span></code> 为 <a class="reference internal" href="../library/functions.html#int" title="int"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> 或某个派生自 <a class="reference internal" href="../library/functions.html#int" title="int"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> 的类时为 <code class="docutils literal notranslate"><span class="pre">True</span></code>。</li>
<li>使用 <a class="reference internal" href="../library/functions.html#issubclass" title="issubclass"><code class="xref py py-func docutils literal notranslate"><span class="pre">issubclass()</span></code></a> 来检查类的继承关系: <code class="docutils literal notranslate"><span class="pre">issubclass(bool,</span> <span class="pre">int)</span></code> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code>，因为 <a class="reference internal" href="../library/functions.html#bool" title="bool"><code class="xref py py-class docutils literal notranslate"><span class="pre">bool</span></code></a> 是 <a class="reference internal" href="../library/functions.html#int" title="int"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> 的子类。 但是，<code class="docutils literal notranslate"><span class="pre">issubclass(float,</span> <span class="pre">int)</span></code> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code>，因为 <a class="reference internal" href="../library/functions.html#float" title="float"><code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code></a> 不是 <a class="reference internal" href="../library/functions.html#int" title="int"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> 的子类。</li>
</ul>
<div class="section" id="multiple-inheritance">
<span id="tut-multiple"></span><h3>9.5.1. 多重继承<a class="headerlink" href="#multiple-inheritance" title="永久链接至标题">¶</a></h3>
<p>Python supports a form of multiple inheritance as well.  A class definition with
multiple base classes looks like this:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">DerivedClassName</span><span class="p">(</span><span class="n">Base1</span><span class="p">,</span> <span class="n">Base2</span><span class="p">,</span> <span class="n">Base3</span><span class="p">):</span>
    <span class="o">&lt;</span><span class="n">statement</span><span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span>
    <span class="o">.</span>
    <span class="o">.</span>
    <span class="o">.</span>
    <span class="o">&lt;</span><span class="n">statement</span><span class="o">-</span><span class="n">N</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>对于多数应用来说，在最简单的情况下，你可以认为搜索从父类所继承属性的操作是深度优先、从左至右的，当层次结构中存在重叠时不会在同一个类中搜索两次。 因此，如果某一属性在 <code class="xref py py-class docutils literal notranslate"><span class="pre">DerivedClassName</span></code> 中未找到，则会到 <code class="xref py py-class docutils literal notranslate"><span class="pre">Base1</span></code> 中搜索它，然后（递归地）到 <code class="xref py py-class docutils literal notranslate"><span class="pre">Base1</span></code> 的基类中搜索，如果在那里未找到，再到 <code class="xref py py-class docutils literal notranslate"><span class="pre">Base2</span></code> 中搜索，依此类推。</p>
<p>真实情况比这个更复杂一些；方法解析顺序会动态改变以支持对 <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-func docutils literal notranslate"><span class="pre">super()</span></code></a> 的协同调用。 这种方式在某些其他多重继承型语言中被称为后续方法调用，它比单继承型语言中的 super 调用更强大。</p>
<p>动态改变顺序是有必要的，因为所有多重继承的情况都会显示出一个或更多的菱形关联（即至少有一个父类可通过多条路径被最底层类所访问）。 例如，所有类都是继承自 <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a>，因此任何多重继承的情况都提供了一条以上的路径可以通向 <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a>。 为了确保基类不会被访问一次以上，动态算法会用一种特殊方式将搜索顺序线性化， 保留每个类所指定的从左至右的顺序，只调用每个父类一次，并且保持单调（即一个类可以被子类化而不影响其父类的优先顺序）。 总而言之，这些特性使得设计具有多重继承的可靠且可扩展的类成为可能。 要了解更多细节，请参阅 <a class="reference external" href="https://www.python.org/download/releases/2.3/mro/">https://www.python.org/download/releases/2.3/mro/</a>。</p>
</div>
</div>
<div class="section" id="private-variables">
<span id="tut-private"></span><h2>9.6. 私有变量<a class="headerlink" href="#private-variables" title="永久链接至标题">¶</a></h2>
<p>那种仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。 但是，大多数 Python 代码都遵循这样一个约定：带有一个下划线的名称 (例如 <code class="docutils literal notranslate"><span class="pre">_spam</span></code>) 应该被当作是 API 的非仅供部分 (无论它是函数、方法或是数据成员)。 这应当被视为一个实现细节，可能不经通知即加以改变。</p>
<p id="index-1">由于存在对于类私有成员的有效使用场景（例如避免名称与子类所定义的名称相冲突），因此存在对此种机制的有限支持，称为 <em class="dfn">名称改写</em>。 任何形式为 <code class="docutils literal notranslate"><span class="pre">__spam</span></code> 的标识符（至少带有两个前缀下划线，至多一个后缀下划线）的文本将被替换为 <code class="docutils literal notranslate"><span class="pre">_classname__spam</span></code>，其中 <code class="docutils literal notranslate"><span class="pre">classname</span></code> 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置，只要它出现在类定义内部就会进行。</p>
<p>名称改写有助于让子类重载方法而不破坏类内方法调用。例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Mapping</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">iterable</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">items_list</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__update</span><span class="p">(</span><span class="n">iterable</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">iterable</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">items_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

    <span class="n">__update</span> <span class="o">=</span> <span class="n">update</span>   <span class="c1"># private copy of original update() method</span>

<span class="k">class</span> <span class="nc">MappingSubclass</span><span class="p">(</span><span class="n">Mapping</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">keys</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
        <span class="c1"># provides new signature for update()</span>
        <span class="c1"># but does not break __init__()</span>
        <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">keys</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">items_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
</pre></div>
</div>
<p>上面的示例即使在 <code class="docutils literal notranslate"><span class="pre">MappingSubclass</span></code> 引入了一个 <code class="docutils literal notranslate"><span class="pre">__update</span></code> 标识符的情况下也不会出错，因为它会在 <code class="docutils literal notranslate"><span class="pre">Mapping</span></code> 类中被替换为 <code class="docutils literal notranslate"><span class="pre">_Mapping__update</span></code> 而在 <code class="docutils literal notranslate"><span class="pre">MappingSubclass</span></code> 类中被替换为 <code class="docutils literal notranslate"><span class="pre">_MappingSubclass__update</span></code>。</p>
<p>请注意，改写规则的设计主要是为了避免意外冲突；访问或修改被视为私有的变量仍然是可能的。这在特殊情况下甚至会很有用，例如在调试器中。</p>
<p>请注意传递给 <code class="docutils literal notranslate"><span class="pre">exec()</span></code> 或 <code class="docutils literal notranslate"><span class="pre">eval()</span></code> 的代码不会将发起调用类的类名视作当前类；这类似于 <code class="docutils literal notranslate"><span class="pre">global</span></code> 语句的效果，因此这种效果仅限于同时经过字节码编译的代码。 同样的限制也适用于 <code class="docutils literal notranslate"><span class="pre">getattr()</span></code>, <code class="docutils literal notranslate"><span class="pre">setattr()</span></code> 和 <code class="docutils literal notranslate"><span class="pre">delattr()</span></code>，以及对于 <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> 的直接引用。</p>
</div>
<div class="section" id="odds-and-ends">
<span id="tut-odds"></span><h2>9.7. 杂项说明<a class="headerlink" href="#odds-and-ends" title="永久链接至标题">¶</a></h2>
<p>有时会需要使用类似于 Pascal 的“record”或 C 的“struct”这样的数据类型，将一些命名数据项捆绑在一起。 这种情况适合定义一个空类:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Employee</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="n">john</span> <span class="o">=</span> <span class="n">Employee</span><span class="p">()</span>  <span class="c1"># Create an empty employee record</span>

<span class="c1"># Fill the fields of the record</span>
<span class="n">john</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;John Doe&#39;</span>
<span class="n">john</span><span class="o">.</span><span class="n">dept</span> <span class="o">=</span> <span class="s1">&#39;computer lab&#39;</span>
<span class="n">john</span><span class="o">.</span><span class="n">salary</span> <span class="o">=</span> <span class="mi">1000</span>
</pre></div>
</div>
<p>一段需要特定抽象数据类型的 Python 代码往往可以被传入一个模拟了该数据类型的方法的类作为替代。 例如，如果你有一个基于文件对象来格式化某些数据的函数，你可以定义一个带有 <code class="xref py py-meth docutils literal notranslate"><span class="pre">read()</span></code> 和 <code class="xref py py-meth docutils literal notranslate"><span class="pre">readline()</span></code> 方法从字符串缓存获取数据的类，并将其作为参数传入。</p>
<p>实例方法对象也具有属性: <code class="docutils literal notranslate"><span class="pre">m.__self__</span></code> 就是带有 <code class="xref py py-meth docutils literal notranslate"><span class="pre">m()</span></code> 方法的实例对象，而 <code class="docutils literal notranslate"><span class="pre">m.__func__</span></code> 则是该方法所对应的函数对象。</p>
</div>
<div class="section" id="iterators">
<span id="tut-iterators"></span><h2>9.8. 迭代器<a class="headerlink" href="#iterators" title="永久链接至标题">¶</a></h2>
<p>到目前为止，您可能已经注意到大多数容器对象都可以使用 <a class="reference internal" href="../reference/compound_stmts.html#for"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">for</span></code></a> 语句:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>
<span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="p">{</span><span class="s1">&#39;one&#39;</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;two&#39;</span><span class="p">:</span><span class="mi">2</span><span class="p">}:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="s2">&quot;123&quot;</span><span class="p">:</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&quot;myfile.txt&quot;</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这种访问风格清晰、简洁又方便。 迭代器的使用非常普遍并使得 Python 成为一个统一的整体。 在幕后，<a class="reference internal" href="../reference/compound_stmts.html#for"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">for</span></code></a> 语句会调用容器对象中的 <a class="reference internal" href="../library/functions.html#iter" title="iter"><code class="xref py py-func docutils literal notranslate"><span class="pre">iter()</span></code></a>。 该函数返回一个定义了 <a class="reference internal" href="../library/stdtypes.html#iterator.__next__" title="iterator.__next__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code></a> 方法的迭代器对象，该方法将逐一访问容器中的元素。 当元素用尽时，<a class="reference internal" href="../library/stdtypes.html#iterator.__next__" title="iterator.__next__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code></a> 将引发 <a class="reference internal" href="../library/exceptions.html#StopIteration" title="StopIteration"><code class="xref py py-exc docutils literal notranslate"><span class="pre">StopIteration</span></code></a> 异常来通知终止 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">for</span></code> 循环。 你可以使用 <a class="reference internal" href="../library/functions.html#next" title="next"><code class="xref py py-func docutils literal notranslate"><span class="pre">next()</span></code></a> 内置函数来调用 <a class="reference internal" href="../library/stdtypes.html#iterator.__next__" title="iterator.__next__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code></a> 方法；这个例子显示了它的运作方式:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="s1">&#39;abc&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span>
<span class="go">&lt;iterator object at 0x00A1DB50&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="go">&#39;a&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="go">&#39;b&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="go">&#39;c&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
    <span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="gr">StopIteration</span>
</pre></div>
</div>
<p>看过迭代器协议的幕后机制，给你的类添加迭代器行为就很容易了。 定义一个 <a class="reference internal" href="../reference/datamodel.html#object.__iter__" title="object.__iter__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__iter__()</span></code></a> 方法来返回一个带有 <a class="reference internal" href="../library/stdtypes.html#iterator.__next__" title="iterator.__next__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code></a> 方法的对象。 如果类已定义了 <code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code>，则 <a class="reference internal" href="../reference/datamodel.html#object.__iter__" title="object.__iter__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__iter__()</span></code></a> 可以简单地返回 <code class="docutils literal notranslate"><span class="pre">self</span></code>:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Reverse</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;Iterator for looping over a sequence backwards.&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">index</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span>

    <span class="k">def</span> <span class="nf">__next__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">index</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">StopIteration</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">index</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">index</span> <span class="o">-</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">index</span><span class="p">]</span>
</pre></div>
</div>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">rev</span> <span class="o">=</span> <span class="n">Reverse</span><span class="p">(</span><span class="s1">&#39;spam&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">iter</span><span class="p">(</span><span class="n">rev</span><span class="p">)</span>
<span class="go">&lt;__main__.Reverse object at 0x00A1DB50&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">rev</span><span class="p">:</span>
<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">m</span>
<span class="go">a</span>
<span class="go">p</span>
<span class="go">s</span>
</pre></div>
</div>
</div>
<div class="section" id="generators">
<span id="tut-generators"></span><h2>9.9. 生成器<a class="headerlink" href="#generators" title="永久链接至标题">¶</a></h2>
<p><a class="reference internal" href="../glossary.html#term-generator"><span class="xref std std-term">Generator</span></a> 是一个用于创建迭代器的简单而强大的工具。 它们的写法类似标准的函数，但当它们要返回数据时会使用 <a class="reference internal" href="../reference/simple_stmts.html#yield"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">yield</span></code></a> 语句。 每次对生成器调用 <a class="reference internal" href="../library/functions.html#next" title="next"><code class="xref py py-func docutils literal notranslate"><span class="pre">next()</span></code></a> 时，它会从上次离开位置恢复执行（它会记住上次执行语句时的所有数据值）。 显示如何非常容易地创建生成器的示例如下:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">reverse</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
        <span class="k">yield</span> <span class="n">data</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
</pre></div>
</div>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">reverse</span><span class="p">(</span><span class="s1">&#39;golf&#39;</span><span class="p">):</span>
<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">f</span>
<span class="go">l</span>
<span class="go">o</span>
<span class="go">g</span>
</pre></div>
</div>
<p>可以用生成器来完成的操作同样可以用前一节所描述的基于类的迭代器来完成。 但生成器的写法更为紧凑，因为它会自动创建 <a class="reference internal" href="../reference/datamodel.html#object.__iter__" title="object.__iter__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__iter__()</span></code></a> 和 <a class="reference internal" href="../reference/expressions.html#generator.__next__" title="generator.__next__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code></a> 方法。</p>
<p>另一个关键特性在于局部变量和执行状态会在每次调用之间自动保存。 这使得该函数相比使用 <code class="docutils literal notranslate"><span class="pre">self.index</span></code> 和 <code class="docutils literal notranslate"><span class="pre">self.data</span></code> 这种实例变量的方式更易编写且更为清晰。</p>
<p>除了会自动创建方法和保存程序状态，当生成器终结时，它们还会自动引发 <a class="reference internal" href="../library/exceptions.html#StopIteration" title="StopIteration"><code class="xref py py-exc docutils literal notranslate"><span class="pre">StopIteration</span></code></a>。 这些特性结合在一起，使得创建迭代器能与编写常规函数一样容易。</p>
</div>
<div class="section" id="generator-expressions">
<span id="tut-genexps"></span><h2>9.10. 生成器表达式<a class="headerlink" href="#generator-expressions" title="永久链接至标题">¶</a></h2>
<p>某些简单的生成器可以写成简洁的表达式代码，所用语法类似列表推导式，将外层为圆括号而非方括号。 这种表达式被设计用于生成器将立即被外层函数所使用的情况。 生成器表达式相比完整的生成器更紧凑但较不灵活，相比等效的列表推导式则更为节省内存。</p>
<p>例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>                 <span class="c1"># sum of squares</span>
<span class="go">285</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">xvec</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">yvec</span> <span class="o">=</span> <span class="p">[</span><span class="mi">7</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">xvec</span><span class="p">,</span> <span class="n">yvec</span><span class="p">))</span>         <span class="c1"># dot product</span>
<span class="go">260</span>

<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">math</span> <span class="k">import</span> <span class="n">pi</span><span class="p">,</span> <span class="n">sin</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">sine_table</span> <span class="o">=</span> <span class="p">{</span><span class="n">x</span><span class="p">:</span> <span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">pi</span><span class="o">/</span><span class="mi">180</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">91</span><span class="p">)}</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">unique_words</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">word</span>  <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">page</span>  <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">())</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">valedictorian</span> <span class="o">=</span> <span class="nb">max</span><span class="p">((</span><span class="n">student</span><span class="o">.</span><span class="n">gpa</span><span class="p">,</span> <span class="n">student</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="k">for</span> <span class="n">student</span> <span class="ow">in</span> <span class="n">graduates</span><span class="p">)</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">data</span> <span class="o">=</span> <span class="s1">&#39;golf&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">list</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">))</span>
<span class="go">[&#39;f&#39;, &#39;l&#39;, &#39;o&#39;, &#39;g&#39;]</span>
</pre></div>
</div>
<p class="rubric">脚注</p>
<table class="docutils footnote" frame="void" id="id2" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>存在一个例外。 模块对象有一个秘密的只读属性 <a class="reference internal" href="../library/stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__dict__</span></code></a>，它返回用于实现模块命名空间的字典；<a class="reference internal" href="../library/stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__dict__</span></code></a> 是属性但不是全局名称。 显然，使用这个将违反命名空间实现的抽象，应当仅被用于事后调试器之类的场合。</td></tr>
</tbody>
</table>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">9. 类</a><ul>
<li><a class="reference internal" href="#a-word-about-names-and-objects">9.1. 名称和对象</a></li>
<li><a class="reference internal" href="#python-scopes-and-namespaces">9.2. Python 作用域和命名空间</a><ul>
<li><a class="reference internal" href="#scopes-and-namespaces-example">9.2.1. 作用域和命名空间示例</a></li>
</ul>
</li>
<li><a class="reference internal" href="#a-first-look-at-classes">9.3. 初探类</a><ul>
<li><a class="reference internal" href="#class-definition-syntax">9.3.1. 类定义语法</a></li>
<li><a class="reference internal" href="#class-objects">9.3.2. 类对象</a></li>
<li><a class="reference internal" href="#instance-objects">9.3.3. 实例对象</a></li>
<li><a class="reference internal" href="#method-objects">9.3.4. 方法对象</a></li>
<li><a class="reference internal" href="#class-and-instance-variables">9.3.5. 类和实例变量</a></li>
</ul>
</li>
<li><a class="reference internal" href="#random-remarks">9.4. 补充说明</a></li>
<li><a class="reference internal" href="#inheritance">9.5. 继承</a><ul>
<li><a class="reference internal" href="#multiple-inheritance">9.5.1. 多重继承</a></li>
</ul>
</li>
<li><a class="reference internal" href="#private-variables">9.6. 私有变量</a></li>
<li><a class="reference internal" href="#odds-and-ends">9.7. 杂项说明</a></li>
<li><a class="reference internal" href="#iterators">9.8. 迭代器</a></li>
<li><a class="reference internal" href="#generators">9.9. 生成器</a></li>
<li><a class="reference internal" href="#generator-expressions">9.10. 生成器表达式</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="errors.html"
                        title="上一章">8. 错误和异常</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="stdlib.html"
                        title="下一章">10. 标准库简介</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../bugs.html">提交 Bug</a></li>
      <li>
        <a href="https://github.com/python/cpython/blob/3.7/Doc/tutorial/classes.rst"
            rel="nofollow">显示源代码
        </a>
      </li>
    </ul>
  </div>
        </div>
      </div>
      <div class="clearer"></div>
    </div>  
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>导航</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="总目录"
             >索引</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python 模块索引"
             >模块</a> |</li>
        <li class="right" >
          <a href="stdlib.html" title="10. 标准库简介"
             >下一页</a> |</li>
        <li class="right" >
          <a href="errors.html" title="8. 错误和异常"
             >上一页</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="https://www.python.org/">Python</a> &#187;</li>
        <li>
          <span class="language_switcher_placeholder">zh_CN</span>
          <span class="version_switcher_placeholder">3.7.3</span>
          <a href="../index.html">文档</a> &#187;
        </li>

          <li class="nav-item nav-item-1"><a href="index.html" >Python 教程</a> &#187;</li>
    <li class="right">
        

    <div class="inline-search" style="display: none" role="search">
        <form class="inline-search" action="../search.html" method="get">
          <input placeholder="快速搜索" type="text" name="q" />
          <input type="submit" value="转向" />
          <input type="hidden" name="check_keywords" value="yes" />
          <input type="hidden" name="area" value="default" />
        </form>
    </div>
    <script type="text/javascript">$('.inline-search').show(0);</script>
         |
    </li>

      </ul>
    </div>  
    <div class="footer">
    &copy; <a href="../copyright.html">版权所有</a> 2001-2019, Python Software Foundation.
    <br />
    Python 软件基金会是一个非盈利组织。
    <a href="https://www.python.org/psf/donations/">请捐助。</a>
    <br />
    最后更新于 4月 09, 2019.
    <a href="../bugs.html">发现了问题</a>？
    <br />
    使用<a href="http://sphinx.pocoo.org/">Sphinx</a>1.8.4 创建。
    </div>

  </body>
</html>